"""通知服务模块"""

import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.mime.image import MIMEImage
import os
import requests
import logging
from typing import Dict, Optional
from config import get_config

class NotificationService:
    """通知服务，负责发送各种类型的告警通知"""
    
    def __init__(self):
        """初始化通知服务"""
        # 配置邮件服务
        self.email_config = {
            'enabled': get_config('notifications.email.enabled', False),
            'smtp_server': get_config('notifications.email.smtp_server', 'smtp.example.com'),
            'smtp_port': get_config('notifications.email.smtp_port', 587),
            'use_tls': get_config('notifications.email.use_tls', True),
            'username': get_config('notifications.email.username', ''),
            'password': get_config('notifications.email.password', ''),
            'from_email': get_config('notifications.email.from_email', 'alerts@example.com'),
            'recipients': get_config('notifications.email.recipients', ['admin@example.com'])
        }
        
        # 配置Webhook服务
        self.webhook_config = {
            'enabled': get_config('notifications.webhook.enabled', False),
            'url': get_config('notifications.webhook.url', 'https://api.example.com/webhook'),
            'headers': get_config('notifications.webhook.headers', {
                'Content-Type': 'application/json'
            }),
            'timeout': get_config('notifications.webhook.timeout', 5.0)
        }
        
        # 配置SMS服务
        self.sms_config = {
            'enabled': get_config('notifications.sms.enabled', False),
            'api_key': get_config('notifications.sms.api_key', ''),
            'api_secret': get_config('notifications.sms.api_secret', ''),
            'endpoint': get_config('notifications.sms.endpoint', 'https://api.sms.example.com/send'),
            'phone_numbers': get_config('notifications.sms.phone_numbers', [''])
        }
        
        # 配置企业微信服务
        self.wecom_config = {
            'enabled': get_config('notifications.wecom.enabled', False),
            'corpid': get_config('notifications.wecom.corpid', ''),
            'agentid': get_config('notifications.wecom.agentid', ''),
            'secret': get_config('notifications.wecom.secret', ''),
            'touser': get_config('notifications.wecom.touser', '@all')
        }
        
        # 配置钉钉服务
        self.dingtalk_config = {
            'enabled': get_config('notifications.dingtalk.enabled', False),
            'webhook_url': get_config('notifications.dingtalk.webhook_url', ''),
            'secret': get_config('notifications.dingtalk.secret', ''),
            'at_mobiles': get_config('notifications.dingtalk.at_mobiles', [])
        }
        
        # 配置日志
        self.logger = self._setup_logger()
        
        print("通知服务已初始化")
        
        # 测试连接（可选）
        if get_config('notifications.test_on_start', False):
            self._test_connections()
    
    def _setup_logger(self) -> logging.Logger:
        """设置日志记录器
        
        Returns:
            日志记录器实例
        """
        logger = logging.getLogger('notification_service')
        logger.setLevel(logging.INFO)
        
        # 添加控制台处理器
        console_handler = logging.StreamHandler()
        formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
        console_handler.setFormatter(formatter)
        logger.addHandler(console_handler)
        
        # 添加文件处理器
        log_file = get_config('notifications.log_file', './logs/notifications.log')
        log_dir = os.path.dirname(log_file)
        if log_dir:
            os.makedirs(log_dir, exist_ok=True)
        
        file_handler = logging.FileHandler(log_file)
        file_handler.setFormatter(formatter)
        logger.addHandler(file_handler)
        
        return logger
    
    def _test_connections(self) -> None:
        """测试各通知渠道连接"""
        self.logger.info("开始测试通知渠道连接...")
        
        if self.email_config['enabled']:
            try:
                # 测试SMTP连接
                server = smtplib.SMTP(
                    self.email_config['smtp_server'],
                    self.email_config['smtp_port'],
                    timeout=10
                )
                if self.email_config['use_tls']:
                    server.starttls()
                if self.email_config['username'] and self.email_config['password']:
                    server.login(self.email_config['username'], self.email_config['password'])
                server.quit()
                self.logger.info("邮件服务器连接测试成功")
            except Exception as e:
                self.logger.error(f"邮件服务器连接测试失败: {str(e)}")
        
        self.logger.info("通知渠道连接测试完成")
    
    def send_notification(self, alert: Dict) -> bool:
        """发送通知
        
        Args:
            alert: 告警信息
            
        Returns:
            是否成功发送至少一种通知
        """
        success = False
        
        # 发送邮件通知
        if self.email_config['enabled']:
            try:
                self._send_email_notification(alert)
                success = True
                self.logger.info(f"邮件通知发送成功: {alert['type']} - {alert['id']}")
            except Exception as e:
                self.logger.error(f"邮件通知发送失败: {str(e)}")
        
        # 发送Webhook通知
        if self.webhook_config['enabled']:
            try:
                self._send_webhook_notification(alert)
                success = True
                self.logger.info(f"Webhook通知发送成功: {alert['type']} - {alert['id']}")
            except Exception as e:
                self.logger.error(f"Webhook通知发送失败: {str(e)}")
        
        # 发送SMS通知
        if self.sms_config['enabled']:
            try:
                self._send_sms_notification(alert)
                success = True
                self.logger.info(f"SMS通知发送成功: {alert['type']} - {alert['id']}")
            except Exception as e:
                self.logger.error(f"SMS通知发送失败: {str(e)}")
        
        # 发送企业微信通知
        if self.wecom_config['enabled']:
            try:
                self._send_wecom_notification(alert)
                success = True
                self.logger.info(f"企业微信通知发送成功: {alert['type']} - {alert['id']}")
            except Exception as e:
                self.logger.error(f"企业微信通知发送失败: {str(e)}")
        
        # 发送钉钉通知
        if self.dingtalk_config['enabled']:
            try:
                self._send_dingtalk_notification(alert)
                success = True
                self.logger.info(f"钉钉通知发送成功: {alert['type']} - {alert['id']}")
            except Exception as e:
                self.logger.error(f"钉钉通知发送失败: {str(e)}")
        
        return success
    
    def _send_email_notification(self, alert: Dict) -> None:
        """发送邮件通知
        
        Args:
            alert: 告警信息
        """
        # 创建邮件
        msg = MIMEMultipart()
        msg['From'] = self.email_config['from_email']
        msg['To'] = ', '.join(self.email_config['recipients'])
        msg['Subject'] = f"[智能交通监管] {alert['severity'].upper()} - {alert['type']}"
        
        # 构建邮件正文
        body_parts = []
        body_parts.append(f"告警类型: {alert['type']}")
        body_parts.append(f"严重程度: {alert['severity']}")
        body_parts.append(f"来源: {alert['source']}")
        body_parts.append(f"时间: {alert['datetime']}")
        body_parts.append(f"告警ID: {alert['id']}")
        body_parts.append("\n详细信息:")
        
        # 添加详细信息
        for key, value in alert['details'].items():
            body_parts.append(f"  {key}: {value}")
        
        body = '\n'.join(body_parts)
        msg.attach(MIMEText(body, 'plain', 'utf-8'))
        
        # 添加快照附件
        if alert.get('snapshot_path') and os.path.exists(alert['snapshot_path']):
            try:
                with open(alert['snapshot_path'], 'rb') as f:
                    img = MIMEImage(f.read())
                    img.add_header('Content-Disposition', 'attachment', 
                                 filename=os.path.basename(alert['snapshot_path']))
                    msg.attach(img)
            except Exception as e:
                self.logger.warning(f"添加快照附件失败: {str(e)}")
        
        # 发送邮件
        server = smtplib.SMTP(
            self.email_config['smtp_server'],
            self.email_config['smtp_port']
        )
        
        if self.email_config['use_tls']:
            server.starttls()
        
        if self.email_config['username'] and self.email_config['password']:
            server.login(self.email_config['username'], self.email_config['password'])
        
        text = msg.as_string()
        server.sendmail(
            self.email_config['from_email'],
            self.email_config['recipients'],
            text
        )
        server.quit()
    
    def _send_webhook_notification(self, alert: Dict) -> None:
        """发送Webhook通知
        
        Args:
            alert: 告警信息
        """
        # 准备Webhook数据
        webhook_data = {
            'alert_id': alert['id'],
            'type': alert['type'],
            'severity': alert['severity'],
            'source': alert['source'],
            'timestamp': alert['timestamp'],
            'datetime': alert['datetime'],
            'details': alert['details']
        }
        
        # 添加快照URL（如果有）
        if alert.get('snapshot_path'):
            # 可以根据需要转换为可访问的URL
            webhook_data['snapshot_path'] = alert['snapshot_path']
        
        # 发送HTTP请求
        response = requests.post(
            self.webhook_config['url'],
            json=webhook_data,
            headers=self.webhook_config['headers'],
            timeout=self.webhook_config['timeout']
        )
        
        response.raise_for_status()  # 如果状态码不是200，抛出异常
    
    def _send_sms_notification(self, alert: Dict) -> None:
        """发送SMS通知
        
        Args:
            alert: 告警信息
        """
        # 构建短信内容（保持简短）
        message = f"【智能交通监管】\n{alert['severity'].upper()}: {alert['type']}\n{alert['datetime']}\n查看详情请登录系统"
        
        # 准备API请求数据
        payload = {
            'api_key': self.sms_config['api_key'],
            'api_secret': self.sms_config['api_secret'],
            'phone_numbers': self.sms_config['phone_numbers'],
            'message': message
        }
        
        # 发送API请求
        response = requests.post(
            self.sms_config['endpoint'],
            json=payload,
            timeout=10.0
        )
        
        response.raise_for_status()  # 如果状态码不是200，抛出异常
    
    def _send_wecom_notification(self, alert: Dict) -> None:
        """发送企业微信通知
        
        Args:
            alert: 告警信息
        """
        # 获取access_token
        token_url = f"https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid={self.wecom_config['corpid']}&corpsecret={self.wecom_config['secret']}"
        token_response = requests.get(token_url)
        token_data = token_response.json()
        
        if token_data.get('errcode') != 0:
            raise Exception(f"获取企业微信access_token失败: {token_data}")
        
        access_token = token_data['access_token']
        
        # 构建消息内容
        message = {
            "touser": self.wecom_config['touser'],
            "msgtype": "markdown",
            "agentid": self.wecom_config['agentid'],
            "markdown": {
                "content": f"# 【智能交通监管】{alert['severity'].upper()} 告警\n"
                           f"## 告警类型: {alert['type']}\n"
                           f"## 时间: {alert['datetime']}\n"
                           f"## 来源: {alert['source']}\n"
                           f"## 告警ID: {alert['id']}\n"
                           f"\n## 详细信息:\n"
            }
        }
        
        # 添加详细信息
        details_text = []
        for key, value in alert['details'].items():
            details_text.append(f"- **{key}**: {value}")
        
        message['markdown']['content'] += '\n'.join(details_text)
        
        # 发送消息
        send_url = f"https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token={access_token}"
        response = requests.post(send_url, json=message)
        
        response_data = response.json()
        if response_data.get('errcode') != 0:
            raise Exception(f"发送企业微信通知失败: {response_data}")
    
    def _send_dingtalk_notification(self, alert: Dict) -> None:
        """发送钉钉通知
        
        Args:
            alert: 告警信息
        """
        import time
        import hmac
        import hashlib
        import base64
        
        # 构建加签（如果配置了secret）
        timestamp = str(round(time.time() * 1000))
        sign = ''
        
        if self.dingtalk_config['secret']:
            secret = self.dingtalk_config['secret']
            secret_enc = secret.encode('utf-8')
            string_to_sign = f"{timestamp}\n{secret}"
            string_to_sign_enc = string_to_sign.encode('utf-8')
            hmac_code = hmac.new(secret_enc, string_to_sign_enc, digestmod=hashlib.sha256).digest()
            sign = base64.b64encode(hmac_code).decode('utf-8')
        
        # 构建请求URL
        url = self.dingtalk_config['webhook_url']
        if sign:
            url += f"&timestamp={timestamp}&sign={sign}"
        
        # 构建消息内容
        message = {
            "msgtype": "markdown",
            "markdown": {
                "title": f"{alert['severity'].upper()} - {alert['type']}",
                "text": f"# 【智能交通监管】{alert['severity'].upper()} 告警\n"
                        f"## 告警类型: {alert['type']}\n"
                        f"## 时间: {alert['datetime']}\n"
                        f"## 来源: {alert['source']}\n"
                        f"## 告警ID: {alert['id']}\n"
            },
            "at": {
                "atMobiles": self.dingtalk_config['at_mobiles'],
                "isAtAll": False
            }
        }
        
        # 添加详细信息
        details_text = []
        for key, value in alert['details'].items():
            details_text.append(f"- **{key}**: {value}")
        
        message['markdown']['text'] += '\n'.join(details_text)
        
        # 发送消息
        response = requests.post(url, json=message)
        
        response_data = response.json()
        if response_data.get('errcode') != 0:
            raise Exception(f"发送钉钉通知失败: {response_data}")
    
    def update_config(self, config_type: str, **kwargs) -> None:
        """更新通知配置
        
        Args:
            config_type: 配置类型 ('email', 'webhook', 'sms', 'wecom', 'dingtalk')
            **kwargs: 要更新的配置项
        """
        config_map = {
            'email': self.email_config,
            'webhook': self.webhook_config,
            'sms': self.sms_config,
            'wecom': self.wecom_config,
            'dingtalk': self.dingtalk_config
        }
        
        if config_type in config_map:
            config = config_map[config_type]
            for key, value in kwargs.items():
                if key in config:
                    config[key] = value
            
            self.logger.info(f"已更新{config_type}通知配置")
        else:
            self.logger.error(f"未知的配置类型: {config_type}")
    
    def get_status(self) -> Dict:
        """获取通知服务状态
        
        Returns:
            各通知渠道的状态信息
        """
        status = {
            'email': {
                'enabled': self.email_config['enabled'],
                'configured': bool(self.email_config['smtp_server'] and self.email_config['from_email'] and self.email_config['recipients'])
            },
            'webhook': {
                'enabled': self.webhook_config['enabled'],
                'configured': bool(self.webhook_config['url'])
            },
            'sms': {
                'enabled': self.sms_config['enabled'],
                'configured': bool(self.sms_config['api_key'] and self.sms_config['endpoint'] and self.sms_config['phone_numbers'])
            },
            'wecom': {
                'enabled': self.wecom_config['enabled'],
                'configured': bool(self.wecom_config['corpid'] and self.wecom_config['agentid'] and self.wecom_config['secret'])
            },
            'dingtalk': {
                'enabled': self.dingtalk_config['enabled'],
                'configured': bool(self.dingtalk_config['webhook_url'])
            }
        }
        
        return status

# 创建全局通知服务实例
notification_service = NotificationService()

# 导出常用方法
def get_notification_service() -> NotificationService:
    """获取通知服务实例的快捷方法"""
    return notification_service